package service

import (
	"encoding/base64"
	"errors"
	"ginblog/enum"
	"ginblog/model"
	"ginblog/utils"
	"golang.org/x/crypto/scrypt"
	"log"
)

var db = utils.Db

type UserService struct {
}

type UserSerInterface interface {
	CheckUser(name string) enum.Code
	CreateUser(data *model.User) enum.Code
	GetUsers(userName string, pageSize, pageNum int) ([]model.User, int64, enum.Code)
	GetUserById(userId int) (users model.User)
	DeleteUser(id int) enum.Code
	UpdatePassword(userId int, password string) enum.Code
	EditUser(id int, data *model.User) enum.Code
	ScryptPw(password string) string
	CheckLogin(username string, password string) (string, enum.Code)
}

// CheckUser 查询用户名是否被使用
func (user *UserService) CheckUser(name string) enum.Code {
	var data model.User
	db.Select("id").Where("username = ?", name).First(&data)
	if data.ID > 0 {
		return enum.ErrorUsernameUsed
	}
	return enum.SUCCESS
}

// CreateUser 添加用户
func (user *UserService) CreateUser(data *model.User) enum.Code {
	// 密码加密
	data.Password = user.ScryptPw(data.Password)

	err := db.Create(data).Error
	if err != nil {
		return enum.ERROR
	}
	return enum.SUCCESS
}

// GetUsers 查询用户列表
func (user *UserService) GetUsers(userName string, pageSize, pageNum int) ([]model.User, int64, enum.Code) {
	var users []model.User
	// 获取数据总数
	var count int64 = 0

	if userName != "" {
		db.Model(&users).Where("username like ?", "%"+userName+"%").Count(&count)
		err := db.Where("username like ?", "%"+userName+"%").Limit(pageSize).Offset((pageNum - 1) * pageSize).Find(&users).Error
		if err != nil {
			return nil, 0, enum.ERROR
		}
		return users, count, enum.SUCCESS
	}
	db.Model(&users).Count(&count)
	err := db.Limit(pageSize).Offset((pageNum - 1) * pageSize).Find(&users).Error
	if err != nil {
		return nil, 0, enum.ERROR
	}
	return users, count, enum.SUCCESS
}

// GetUserById 根据id查询用户
func (user *UserService) GetUserById(userId int) (users model.User) {
	users = model.User{}
	err := db.First(&users, userId).Error
	if err != nil {
		errors.New("网络异常，请稍后再试！")
		return
	}
	return users
}

// EditUser 编辑用户，一般只能编辑用户的基本信息，不能编辑密码，密码一般时独立的接口
func (user *UserService) EditUser(id int, data *model.User) enum.Code {

	// 查询该用户是否存在
	editUser := user.GetUserById(id)
	if editUser.ID < 1 {
		return enum.ErrorUserNotExist
	}
	// 编辑用户
	maps := make(map[string]interface{})
	if data.Username != "" || len(data.Username) != 0 {
		maps["username"] = data.Username
	}
	maps["role"] = data.Role

	err := db.Model(&model.User{}).Where("id = ? and deleted_at is null", id).Updates(maps).Error
	if err != nil {
		return enum.ERROR
	}
	return enum.SUCCESS
}

// UpdatePassword 修改密码
func (user *UserService) UpdatePassword(userId int, password string) enum.Code {

	password = user.ScryptPw(password)

	// 查看密码是否重复
	editUser := user.GetUserById(userId)
	if editUser.Password == password {
		return enum.ErrorPasswordRepeat
	}

	// 编辑用户
	maps := make(map[string]interface{})
	// 对密码进行加密
	maps["password"] = password

	err := db.Model(&model.User{}).Where("id = ? and deleted_at is null", userId).Updates(maps).Error
	if err != nil {
		return enum.ERROR
	}

	return enum.SUCCESS
}

// DeleteUser 删除用户
func (user *UserService) DeleteUser(id int) enum.Code {
	users := model.User{}
	// 查询该用户是否被删除
	editUser := user.GetUserById(id)
	if editUser.ID < 1 {
		return enum.ErrorUserNotExist
	}

	// 删除用户，软删除
	err := db.Where("id = ?", id).Delete(&users).Error
	if err != nil {
		return enum.ERROR
	}
	return enum.SUCCESS
}

// ScryptPw 密码加密
func (user *UserService) ScryptPw(password string) string {
	const KeyLen = 10
	// 设置一个盐
	salt := make([]byte, 8)
	salt = []byte{6, 28, 38, 77, 25, 225, 27, 11}

	// N：必须要大于1，且为2的幂次方
	HashPw, err := scrypt.Key([]byte(password), salt, 16384, 8, 1, KeyLen)
	if err != nil {
		// 失败后输出日志再关闭
		log.Fatal(err)
	}
	fpw := base64.StdEncoding.EncodeToString(HashPw)
	return fpw
}

// CheckLogin 后台登录验证
func (user *UserService) CheckLogin(username string, password string) (string, enum.Code) {
	users := model.User{}

	// 查询该用户
	db.Where("username = ?", username).First(&users)
	// 判断用户是否存在
	if users.ID == 0 {
		return "", enum.ErrorUserNotExist
	}
	// 判断密码是否正确
	pw := user.ScryptPw(password)
	if users.Password != pw {
		return "", enum.ErrorPasswordWrong
	}

	// 判断是不是管理员
	if users.Role != 1 {
		return "", enum.ErrorUserNoRight
	}
	return users.Username, enum.SUCCESS
}
